//Three.js 提供了一些辅助对象，添加到场景中之后就可以显示出场景中的不可见对象（例如光照、相机等）
//-- DirectionalLightHelper，它会绘制一个方形的小平面代表方向光的位置，一条连接光源与目标点的直线，代表了光的方向

// GUI  调试面板库
// 辅助类：THREE.Color 不能直接被 dat.GUI 修改，所以需要转换成 HEX 字符串（#ffffff 格式）

import { useEffect } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import * as dat from 'dat.gui'; // 导入 dat.GUI

function SimpleCubeWithLight() {
  useEffect(() => {
    // ---------------初始化场景、相机、渲染器
    const scene = new THREE.Scene();

    const fov = 45;
    const aspect = 2; // canvas 的默认宽高 300:150
    const near = 0.1;
    const far = 100;
    const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    camera.position.set(0, 10, 10);

    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // 轨道控制器，实现围绕观察点旋转相机
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.target.set(0, 5, 5); // 观察点
    controls.update();

    // -----------------------物体
    // 二维平面底座
    // 1、设置纹理
    const planeSize = 40;
    const loader = new THREE.TextureLoader();
    const texture = loader.load('/masaike.png');
    texture.wrapS = THREE.RepeatWrapping; // 纹理重复-水平包裹
    texture.wrapT = THREE.RepeatWrapping;
    texture.magFilter = THREE.NearestFilter;
    const repeats = planeSize / 2;
    texture.repeat.set(repeats, repeats);
    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
    const planeMat = new THREE.MeshPhongMaterial({
      map: texture,
      side: THREE.DoubleSide,
    });
    const mesh = new THREE.Mesh(planeGeo, planeMat);
    mesh.rotation.x = Math.PI * -0.5;
    scene.add(mesh);
    // 几何体
    const cubeSize = 3;
    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
    const cubeMat = new THREE.MeshPhongMaterial({ color: '#8AC' });
    const mesh2 = new THREE.Mesh(cubeGeo, cubeMat);
    mesh2.position.set(cubeSize + 2, cubeSize / 2, 0);
    scene.add(mesh2);

    const sphereRadius = 1.5;
    const sphereWidthDivisions = 32;
    const sphereHeightDivisions = 16;
    const sphereGeo = new THREE.SphereGeometry(
      sphereRadius,
      sphereWidthDivisions,
      sphereHeightDivisions
    );
    const sphereMat = new THREE.MeshPhongMaterial({ color: '#CA8' });
    const mesh3 = new THREE.Mesh(sphereGeo, sphereMat);
    mesh3.position.set(-sphereRadius - 4, sphereRadius, 0);
    scene.add(mesh3);

    // ----------------------------光源
    // 1创建聚光灯
    const color = 0xffffff;
    const intensity = 1;
    const light = new THREE.SpotLight(color, intensity);
    scene.add(light);
    scene.add(light.target);

    const helper = new THREE.SpotLightHelper(light);
    scene.add(helper);

    // ------------------------------gui
    // 2创建辅助类帮助gui修改属性
    // 修改颜色
    class ColorGUIHelper {
      constructor(object, prop) {
        this.object = object;
        this.prop = prop;
      }
      // 当读取value时，返回this.prop (light.color) 的 HEX 字符串格式（如 "#ffffff")
      get value() {
        return `#${this.object[this.prop].getHexString()}`;
      }
      // 当修改value时，将 HEX 字符串（如 "#ff0000"）设置给 this.prop (light.color)
      set value(hexString) {
        this.object[this.prop].set(hexString);
      }
    }
    // 弧度、角度转换
    class DegRadHelper {
      constructor(obj, prop) {
        this.obj = obj;
        this.prop = prop;
      }
      get value() {
        return THREE.MathUtils.radToDeg(this.obj[this.prop]); //radToDeg弧度转角度
      }
      set value(v) {
        this.obj[this.prop] = THREE.MathUtils.degToRad(v); // degToRad角度转弧度
      }
    }
    // 添加折叠文件，修改位置
    function makeXYZGUI(gui, vector3, name, onChangeFn) {
      const folder = gui.addFolder(name); // 在控件内创建一个折叠文件夹
      folder.add(vector3, 'x', -10, 10).onChange(onChangeFn); // 为 vector3.x 添加一个滑块控件，范围从 -10 到 10
      folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
      folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
      folder.open();
    }
    // 更新辅助对象
    function updateLight() {
      helper.update();
    }
    updateLight();

    // 3添加控件gui
    const gui = new dat.GUI(); // 创建控件对象gui
    // 添加颜色控件
    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
    // 强度
    gui.add(light, 'intensity', 0, 20, 1);

    // 通过angle属性设置圆锥顶部角度
    gui
      .add(new DegRadHelper(light, 'angle'), 'value', 0, 90)
      .name('angle')
      .onChange(updateLight);
    // 通过设置 penumbra 属性来定义内圆锥
    gui.add(light, 'penumbra', 0, 1, 0.01);
    makeXYZGUI(gui, light.position, 'position', updateLight);

    // --------------------------------渲染
    function animate() {
      requestAnimationFrame(animate);
      renderer.render(scene, camera);
    }
    animate();

    // 清理函数
    return () => {
      document.body.removeChild(renderer.domElement);
      gui.destroy(); // 由于useEffect 执行两次，所以在组件卸载时销毁 GUI
    };
  }, []);

  return <div />;
}

export default SimpleCubeWithLight;
